function [err, ErrMessage, Info] = CheckBrikHEAD (Info)
%
%   [err, ErrMessage, InfoOut] = CheckBrikHEAD (Info)
%
%Purpose:
%   Checks to determine if the fields in Info are appropriate AFNI style
%   
%   
%Input Parameters:
%   Info is a structure containing all the Header fields, 
%   
%   
%Output Parameters:
%   err : 0 No Problem
%       : 1 Mucho Problems
%   ErrMessage
%   Vector Indexing in error messages is done a la matlab. 
%   so DATASET_RANK(1) in the error message refers to the first value in DATASET_RANK
%   which would be DATASET_RANK[0] in AFNI
%   InfoOut
%   same as Info    , but with the empty optional fields trimmed out
%
%Key Terms:
%   
%More Info :
%   BrikInfo for list of Mandatory fields and AFNI's README.attributes
%   
%   
%
%     Author : Ziad Saad
%     Date : Fri Apr 6 09:48:49 PDT 2001
%     LBC/NIMH/ National Institutes of Health, Bethesda Maryland


%Define the function name for easy referencing
FuncName = 'CheckBrikHEAD';

%Debug Flag
DBG = 1;

%initailize return variables
err = 1;

ErrMessage = '';

%Mandatory Fields Specs 

MandatoryFieldNames = 'DATASET_RANK~DATASET_DIMENSIONS~TYPESTRING~SCENE_DATA~ORIENT_SPECIFIC~ORIGIN~DELTA';
N_Mandatory = WordCount(MandatoryFieldNames, '~');

%check if the mandatory fields are present
for (im = 1:1:N_Mandatory),
	%Check that all the Mandatory Fields have been specified.
	[err, CurName] = GetWord(MandatoryFieldNames, im, '~');
	if(~isfield(Info, CurName)),
		err = 1; ErrMessage = sprintf('Error %s: Field %s must be specified for the Header to be proper.', FuncName, CurName);
		warndlg(ErrMessage);
		return;
	end
end

%Now Get all the rules
[err, ErrMessage, Rules] = HEAD_Rules; 
if (err), ErrMessage = sprintf('Error %s: Error in HEAD_RULES.\n%s', FuncName, ErrMessage); errordlg(ErrMessage); return; end
N_Rules = length(Rules);

%auto checks and cleanup of empty fields
for (ir = 1:1:N_Rules),
			%fprintf(1,'Checking %s ...', Rules(ir).Name);
	%Check that all the Remaining Fields are OK.
	if (isfield(Info, Rules(ir).Name)), 
		if (isempty(getfield(Info, Rules(ir).Name))),
			%fprintf(1,' Empty .\n');
			%remove this field if it is empty, this reduces the clutter of the ascii .HEAD file
			Info = rmfield(Info, Rules(ir).Name);
		else 
				%fprintf(1,'Not Empty .\n');
			%check for type coherence
			if (ischar(getfield(Info, Rules(ir).Name))),
				if (Rules(ir).isNum),
					err = 1; ErrMessage = sprintf('Error %s: Field %s type (string or numerical) is wrong.', FuncName, Rules(ir).Name);warndlg(ErrMessage);return;
				end
			else %a number, verify type
				if (Rules(ir).isNum == 1 & ~isint(getfield(Info, Rules(ir).Name))),
					err = 1; ErrMessage = sprintf('Error %s: Field %s type must be an integer.', FuncName, Rules(ir).Name);
				end
			end
			%check for length specs
			if (~isempty(Rules(ir).Length)),
				if (length(getfield(Info,Rules(ir).Name)) ~= Rules(ir).Length),
					err = 1; ErrMessage = sprintf('Error %s: Field %s length must be %d.', FuncName, Rules(ir).Name, Rules(ir).Length);warndlg(ErrMessage);return;
				end
			end
			%check for minimum length specs
			if (~isempty(Rules(ir).minLength)),
				if (length(getfield(Info,Rules(ir).Name)) < Rules(ir).minLength),
					err = 1; ErrMessage = sprintf('Error %s: Field %s length must be at least %d.', FuncName, Rules(ir).Name, Rules(ir).minLength);warndlg(ErrMessage);return;
				end
			end
		end
	end
end



%Further Field specfic checks
	%For Mandatory Fields
		if (Info.DATASET_RANK(1) ~= 3),
			err = 1; ErrMessage = sprintf('Error %s: DATASET_RANK(1) must be 3', FuncName); errordlg(ErrMessage); return;
		end
		if (length(Info.DATASET_RANK) < 8),
			v = zeros(1,8); v(1:length(Info.DATASET_RANK)) = Info.DATASET_RANK;
			Info.DATASET_RANK = v;
		end
		if (min(Info.DATASET_DIMENSIONS(1:3)) < 1),
			err = 1; ErrMessage = sprintf('Error %s: All values in DATASET_DIMENSIONS must be >= 1', FuncName); errordlg(ErrMessage); return;
		end
		if (length(Info.DATASET_DIMENSIONS) < 5),
			v = zeros(1,5); v(1:length(Info.DATASET_DIMENSIONS)) = Info.DATASET_DIMENSIONS;
			Info.DATASET_DIMENSIONS = v;
		end
		
		
		List = {'3DIM_HEAD_ANAT', '3DIM_HEAD_FUNC', '3DIM_GEN_ANAT', '3DIM_GEN_FUNC'}; 
		s = 0;
		for (il = 1:1:length(List)),
			s = s + strcmp(Info.TYPESTRING, char(List(il)));
		end
		if (s ~= 1),
			err = 1; ErrMessage = sprintf('Error %s: TYPESTRING must be one of \n3DIM_HEAD_ANAT, 3DIM_HEAD_FUNC, 3DIM_GEN_ANAT or 3DIM_GEN_FUNC', FuncName); errordlg(ErrMessage); return;	
		end

		if (Info.SCENE_DATA(1) < 0 |  Info.SCENE_DATA(1) > 2),
			err = 1; ErrMessage = sprintf('Error %s: SCENE_DATA(1) must be between 0 and 2', FuncName); errordlg(ErrMessage); return;
		end
		if (Info.SCENE_DATA(2) < 0 |  Info.SCENE_DATA(2) > 11),
			err = 1; ErrMessage = sprintf('Error %s: SCENE_DATA(2) must be between 0 and 11', FuncName); errordlg(ErrMessage); return;
		end
		if (Info.SCENE_DATA(3) < 0 |  Info.SCENE_DATA(3) > 3),
			err = 1; ErrMessage = sprintf('Error %s: SCENE_DATA(3) must be between 0 and 3', FuncName); errordlg(ErrMessage); return;
		end

		if (Info.ORIENT_SPECIFIC(1) < 0 |  Info.ORIENT_SPECIFIC(1) > 5),
			err = 1; ErrMessage = sprintf('Error %s: ORIENT_SPECIFIC(1) must be between 0 and 5', FuncName); errordlg(ErrMessage); return;
		end


		%For remaining fields

		if (isfield(Info, 'BRICK_STATS')),
			if (length(Info.BRICK_STATS) ~= 2.*Info.DATASET_RANK(2)), 
				err = 1; ErrMessage = sprintf('Error %s: Info.BRICK_STATS should contain %d values (%d found).', FuncName, 2.*Info.DATASET_RANK(2), length(Info.BRICK_STATS)); errordlg(ErrMessage); return; 
			end
		end

		if (isfield(Info, 'BRICK_TYPES')),
			if (length(Info.BRICK_TYPES) ~= Info.DATASET_RANK(2)), 
				err = 1; ErrMessage = sprintf('Error %s: Info.BRICK_TYPES should contain %d values (%d found).', FuncName, Info.DATASET_RANK(2), length(Info.BRICK_TYPES)); errordlg(ErrMessage); return; 	
			end
		end

		if (isfield(Info, 'BRICK_FLOAT_FACS')),
			if (length(Info.BRICK_FLOAT_FACS) ~= Info.DATASET_RANK(2)), 
				err = 1; ErrMessage = sprintf('Error %s: Info.BRICK_FLOAT_FACS should contain %d values (%d found).', FuncName, Info.DATASET_RANK(2), length(Info.BRICK_FLOAT_FACS)); errordlg(ErrMessage); return; 	
			end
		end

		if (isfield(Info, 'TAXIS_NUMS')),
			if (~isfield(Info, 'TAXIS_FLOATS')),
				err = 1; ErrMessage = sprintf('Error %s: TAXIS_FLOATS must be specified along with TAXIS_NUMS', FuncName); errordlg(ErrMessage); return;
			end
			if (Info.TAXIS_NUMS(1) ~= Info.DATASET_RANK(2)),
				err = 1; ErrMessage = sprintf('Error %s: TAXIS_NUMS(1) must be equal to DATASET_RANK(2)', FuncName); errordlg(ErrMessage); return;
			end

			if (Info.TAXIS_NUMS(2) & (~isfield(Info,'TAXIS_OFFSETS') | isempty(Info.TAXIS_OFFSETS))),
				err = 1; ErrMessage = sprintf('Error %s: TAXIS_OFFSETS must have a value if TAXIS_NUMS(2) is != 0', FuncName); errordlg(ErrMessage); return;
			end
		end

		if (isfield(Info, 'IDCODE_DATE')),
			if (length(Info.IDCODE_DATE) > 46),
				err = 1; ErrMessage = sprintf('Error %s: IDCODE_DATE must be less than 46 characters.', FuncName); errordlg(ErrMessage); return;
			end
		end

		if (isfield(Info, 'BYTEORDER_STRING')),
			if (~strcmp(Info.BYTEORDER_STRING, 'LSB_FIRST') & ~strcmp(Info.BYTEORDER_STRING, 'MSB_FIRST')),
				err = 1; ErrMessage = sprintf('Error %s: BYTEORDER_STRING must be either MSB_FIRST or LSB_FIRST', FuncName); errordlg(ErrMessage); return;
			end
		end

		if (isfield(Info, 'BRICK_LABS') & (WordCount(Info.BRICK_LABS, '~')-1 ~= Info.DATASET_RANK(2))),
			%err = 1; ErrMessage = sprintf('Error %s: There has to be exactly %d ~ separated labels in BRICK_LABS', FuncName, Info.DATASET_RANK(2)); errordlg(ErrMessage); return;	
         if (WordCount(Info.BRICK_LABS, '~') > 1),
            fprintf(2, 'Warning %s: You have %d sub-bricks but %d ~ separated labels.\n', FuncName, Info.DATASET_RANK(2), WordCount(Info.BRICK_LABS, '~')); 
         end	
      end

		if (isfield(Info, 'NOTES_COUNT') & (Info.NOTES_COUNT < 0 | Info.NOTES_COUNT > 999)),
			err = 1; ErrMessage = sprintf('Error %s: NOTES_COUNT must be between 0 and 999.', FuncName); errordlg(ErrMessage); return;
		end 

		if (isfield(Info, 'WARP_TYPE') & (Info.WARP_TYPE(1) ~= 0 & Info.WARP_TYPE(1) ~= 1)),
			err = 1; ErrMessage = sprintf('Error %s: WARP_TYPE(1) must be 0 or 1.', FuncName); errordlg(ErrMessage); return;
		end

		if (isfield(Info, 'WARP_DATA')),
   		if (rem(length(Info.WARP_DATA), 30)),
				err = 1; ErrMessage = sprintf('Error %s: The number of elements in WARP_DATA must be a multiple of 30.\nOtherwise BLTs would taste rotten.', FuncName); errordlg(ErrMessage); return;
			end
		end

		if (isfield(Info, 'MARKS_FLAGS')),
			if (Info.MARKS_FLAGS(1) ~= 1 & Info.MARKS_FLAGS(1) ~= 2),
				err = 1; ErrMessage = sprintf('Error %s: MARKS_FLAGS(1) must be 0 or 1.', FuncName); errordlg(ErrMessage); return;	
			end
			if (Info.MARKS_FLAGS(2) ~= 1),
				err = 1; ErrMessage = sprintf('Error %s: MARKS_FLAGS(2) must be 1.', FuncName); errordlg(ErrMessage); return;	
			end
		end

		if (isfield(Info, 'TAGSET_NUM')),
			if (Info.TAGSET_NUM(1) > 100),
				err = 1; ErrMessage = sprintf('Error %s: TAGSET_NUM(1) should not be larger than 100.', FuncName); errordlg(ErrMessage); return;
			end
		end

		if (isfield(Info, 'TAGSET_NUM') & isfield(Info, 'TAGSET_FLOATS')),
			if (length(Info.TAGSET_FLOATS) ~= (Info.TAGSET_NUM(1) .* Info.TAGSET_NUM(2)) ),   % Ask Ziad about this later
				err = 1; ErrMessage = sprintf('Error %s: Length of TAGSET_FLOATS must equal TAGSET_NUM(1) * TAGSET_NUM(2).', FuncName); errordlg(ErrMessage); return;	
			end
		end

		if (isfield(Info, 'TAGSET_NUM') & isfield(Info, 'TAGSET_LABELS')),
			if (WordCount(Info.TAGSET_LABELS, '~') ~= Info.TAGSET_NUM(1)),   % Ask Ziad later
				err = 1; ErrMessage = sprintf('Error %s: TAGSET_LABELS must contain TAGSET_NUM(1) ~ delimited strings.', FuncName); errordlg(ErrMessage); return;	
			end
		end

		if (isfield(Info, 'BRICK_TYPES')),
			if (~isempty(unique(setdiff(Info.BRICK_TYPES, [0 1 3 5]))))
				err = 1; ErrMessage = sprintf('Error %s: BRICK_TYPES only types 0 1 3 5 are supported.', FuncName); errordlg(ErrMessage); return;	
			end
		end

		%checks on the rotate fields
		if (isfield(Info, 'VOLREG_ROTCOM_NUM')),
			for (i=1:1:Info.VOLREG_ROTCOM_NUM),
					sp = pad_strn(num2str(i-1), '0', 6, 1);
					spad = sprintf('~isfield(Info, ''VOLREG_MATVEC_%s'') | isempty(Info.VOLREG_MATVEC_%s) | ischar(Info.VOLREG_MATVEC_%s) | length(Info.VOLREG_MATVEC_%s) ~= 12', sp, sp, sp, sp);
					if (eval([ spad ])),
						err = 1; ErrMessage = sprintf('Error %s: Undefined VOLREG_MATVEC_%s or bad type (strings) or bad length (~=12)', FuncName, sp);errordlg(ErrMessage); return;  
					end
			end
		end

		%check on the NOT_NUMBER_... fields
		if (~isfield(Info, 'NOTES_COUNT') & isfield(Info, 'NOTE_NUMBER_001')),
			Info = rmfield(Info, 'NOTE_NUMBER_001');
		end

		%check on the HISTORY field
		if (isfield(Info, 'HISTORY_NOTE')),
			vtmp = unique(double(Info.HISTORY_NOTE));
			if (~isempty(intersect([13 10 34 9 7 11 8], vtmp))),
				err = 1; ErrMessage = sprintf('Error %s: HISTORY_NOTE has not been TomRossed (formatted) properly.', FuncName); errordlg(ErrMessage);return;  				
			end
		end
		
%check on field groups

err = 0;
return;

